package com.melody.renderview.view;

import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.SurfaceTexture;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.ViewTreeObserver;
import android.widget.TextView;

import com.melody.renderview.encoder.ViewEncoder;

/**
 * Created by Wenhuan Cai on 2017/8/23.
 * 思考方法如下：
 * 方法一：获取drawingCache bitmap 然后调用opengl es的texSubImage2D方法贴到纹理中，继而调用mediacodec编码，
 *        该方法依赖于截获bitmap的帧率，此处并未实现
 * 方法二：渲染view的canvas到对应surface的canvas，该surface可以由surfaceview提供，也可以由mediacodec提供，还可以由自己构造提供
 *        该方案理论对所有view都试用（本处采用textview实现），原理就是在ondraw中将画view的内容重新画到以上提及的surface中
 *        本次实现较为简单，有很多需要改进地方，比如在ondraw中不但画了一次本身view内容，又画了一次到surfaceview的surface中，可以开启新的线程画，提高绘制效率
 *        以及背景的绘制本次直接写死，应该由外界传入。该方法依赖于ondraw的执行，若某些效果不走ondraw流程，需要进一步研究。
 */
public class RenderView extends TextView{
    public static final String TAG = RenderView.class.getSimpleName();

    private Surface mSurface;

    private SurfaceTexture mSurfaceTexture;

    private SurfaceHolder mSurfaceHolder;

    private ViewEncoder mViewEncoder;

    private boolean isRenderToSurfaceView;

    private boolean isRenderToMediaCodec;

    public void setSurfaceTexture(SurfaceTexture surfaceTexture) {
        this.mSurfaceTexture = surfaceTexture;
    }

    public void setSurface(Surface surface) {
        this.mSurface = surface;
    }

    public void setSurfaceHolder(SurfaceHolder surfaceHolder) {
        this.mSurfaceHolder = surfaceHolder;
    }

    public void setViewEncoder(ViewEncoder viewEncoder) {
        this.mViewEncoder = viewEncoder;
    }

    public void setIsRenderToSurfaceView(boolean isRenderToSurfaceView) {
        this.isRenderToSurfaceView = isRenderToSurfaceView;
    }

    public void setIsRenderToMediaCodec(boolean isRenderToMediaCodec) {
        this.isRenderToMediaCodec = isRenderToMediaCodec;
    }

    public RenderView(Context context) {
        super(context);
        setWillNotDraw(false);
        setDrawingCacheEnabled(false);
        addOnPreDrawListener();
    }


    public RenderView(Context context, AttributeSet attrs) {
        super(context, attrs);
        setWillNotDraw(false);
        setDrawingCacheEnabled(false);
        addOnPreDrawListener();
    }

    public RenderView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        setWillNotDraw(false);
        setDrawingCacheEnabled(false);
        addOnPreDrawListener();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
            if (isRenderToSurfaceView) {
                rendViewToSurfaceView(canvas);
            }

            if (isRenderToMediaCodec) {
                rendViewToMediaCodec(canvas);
            }
        }
    }

    /**
     * 渲染到opengl 本次未实现
     * @param canvas
     */
    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
    private void rendViewToOpenGL(Canvas canvas){
        Log.d(TAG, "mSurface " + mSurface + " mSurfaceTexture " + mSurfaceTexture);
        try {
            /*if (mSurface != null) {
                Canvas surfaceCanvas = mSurface.lockCanvas(null);
                super.dispatchDraw(surfaceCanvas);
                mSurface.unlockCanvasAndPost(surfaceCanvas);

                *//*mSurface.release();
                mSurface = null;
                mSurface = new Surface(mSurfaceTexture);*//*
            }*/
        } catch (Surface.OutOfResourcesException e) {
            e.printStackTrace();
        }
    }

    private void rendViewToMediaCodec(Canvas canvas){
        Log.d(TAG, "mSurface " + mSurface + " mSurfaceTexture " + mSurfaceTexture);
        try {
            if (mSurface != null) {
                mViewEncoder.drainEncoder(false);
                Canvas surfaceCanvas = mSurface.lockCanvas(null);
                surfaceCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); //清空画布内容
                surfaceCanvas.drawColor(Color.parseColor("#ffcc0000"));
                super.onDraw(surfaceCanvas);
                mSurface.unlockCanvasAndPost(surfaceCanvas);
            }
        } catch (Surface.OutOfResourcesException e) {
            e.printStackTrace();
        }
    }


    /**
     * 渲染view内容到SurfaceView
     * @param canvas
     */
    private void rendViewToSurfaceView(Canvas canvas){
        Log.d(TAG, "mSurfaceHolder " + mSurfaceHolder);
        try {
            if (mSurfaceHolder != null) {
                Canvas surfaceCanvas = mSurfaceHolder.lockCanvas();
                surfaceCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); //清空画布内容
                surfaceCanvas.drawColor(Color.parseColor("#ffcc0000"));
                super.onDraw(surfaceCanvas);
                mSurfaceHolder.unlockCanvasAndPost(surfaceCanvas);
            }
        } catch (Surface.OutOfResourcesException e) {
            e.printStackTrace();
        }
    }


    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    private void addOnPreDrawListener() {

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {

            final ViewTreeObserver mObserver = getViewTreeObserver();
            if (mObserver != null) {
                mObserver.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {

                    @Override
                    public boolean onPreDraw() {
                        if (isDirty()) {
                            Log.d(TAG, "addOnPreDrawListener invalidate");
                            invalidate();
                        }
                        return true;
                    }
                });
            }
        }
    }
}
